import numpy as np
import core

def to_array(x):
    """
    将输入的值转换为NumPy数组。

    Args:
        x: 输入的值。

    Returns:
        numpy.ndarray: 转换后的NumPy数组。
    """

    # 使用np.isscalar(x)来判断x是否是ndarray实例
    return np.array(x) if np.isscalar(x) else x


def to_variable(obj):
    """
    将输入的对象转换为Variable实例。

    Args:
        obj: 输入的对象。

    Returns:
        Variable: 转换后的Variable实例。
    """
    return obj if is_variable(obj) else core.variable.Variable(obj)


def is_variable(obj):
    """
    判断输入的对象是否是Variable实例。

    Args:
        obj: 输入的对象。

    Returns:
        bool: 如果是Variable实例返回True，否则返回False。
    """

    return hasattr(obj, 'is_variable')  # 检查是否有 'is_variable' 属性


def to_tuple(value):
    """
    将输入的值转换为元组。

    Args:
        value: 输入的值。

    Returns:
        tuple: 转换后的元组。
    """

    return value if isinstance(value, tuple) else (value,)


def pair(x):
    """
    将输入的值转换为二元组。

    Args:
        x: 输入的值。

    Returns:
        tuple: 转换后的二元组。
    """

    if isinstance(x, int):
        return (x, x)
    elif isinstance(x, tuple):
        assert len(x) == 2
        return x
    else:
        raise ValueError


def logsumexp(x, axis=1):
    """
    计算log-sum-exp。

    Args:
        x (numpy.ndarray): 输入的NumPy数组。
        axis (int): 指定的轴。

    Returns:
        numpy.ndarray: 计算结果。
    """

    xp = core.cuda.cuda_module
    m = x.max(axis=axis, keepdims=True)
    y = x - m
    xp.exp(y, out=y)
    s = y.sum(axis=axis, keepdims=True)
    xp.log(s, out=s)
    m += s
    return m


def accuracy(y, t):
    """
    [警告] 此函数不可导。

    计算分类准确度。

    Args:
        y (Variable or numpy.ndarray): 模型的输出。
        t (Variable or numpy.ndarray): 目标标签。

    Returns:
        Variable: 分类准确度。
    """

    y, t = to_variable(y), to_variable(t)

    pred = y.data.argmax(axis=1).reshape(t.shape)
    result = (pred == t.data)
    acc = result.mean()
    return to_variable(to_array(acc))


def clip_grads(grads, max_norm):
    """
    根据最大梯度范数裁剪梯度。

    Args:
        grads (list of numpy.ndarray): 梯度列表。
        max_norm (float): 最大梯度范数。
    """

    total_norm = 0
    for grad in grads:
        total_norm += np.sum(grad ** 2)
    total_norm = np.sqrt(total_norm)

    rate = max_norm / (total_norm + 1e-6)
    if rate < 1:
        for grad in grads:
            grad *= rate
